﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;

using LowLevelGraphics.Filter;

namespace LowLevelGraphics
{
    ///// <summary>
    ///// Unsafe Bitmap class.
    ///// This class replaces the normal .net bitmap class.
    ///// All constructors have been integrated as far as possible
    ///// </summary>    
    public class UnsafeBitmap24 : UnsafeBitmap
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="UnsafeBitmap24"/> class.
        /// </summary>
        /// <param name="_stream">The _stream.</param>
        public UnsafeBitmap24(Stream _stream)
            : this(new Bitmap(_stream))
        {
        }

        /// <summary>
        /// See Bitmap(OriginalImage, szSize)
        /// </summary>
        /// <param name="_originalImage"></param>
        /// <param name="_szSize"></param>
        public UnsafeBitmap24(Image _originalImage, Size _szSize)
            : this(new Bitmap(_originalImage, _szSize))
        {
        }

        /// <summary>
        /// See Image.FromHBitmap(IntPtr _hBitmap)
        /// </summary>
        /// <param name="_hBitmap"></param>
        public UnsafeBitmap24(IntPtr _hBitmap)
            : this(Image.FromHbitmap(_hBitmap))
        {
        }

        /// <summary>
        /// See Image.FromHBitmap(IntPtr _hBitmap, IntPtr _hPalette)
        /// </summary>
        /// <param name="_hBitmap"></param>
        /// <param name="_hPalette"></param>
        public UnsafeBitmap24(IntPtr _hBitmap, IntPtr _hPalette)
            : this(Image.FromHbitmap(_hBitmap, _hPalette))
        {
        }

        ///// <summary>
        ///// Use this to get an Image stream with or no embedded color management
        ///// <seealso cref="Image.FromStream">Image.FromStream</seealso> for reference
        ///// </summary>
        ///// <param name="_stream"></param>
        ///// <param name="_bUseEmbeddedColorManagement"></param>
        ///// <param name="_bValidateData"></param>
        //public UnsafeBitmap24(Stream _stream, bool _bUseEmbeddedColorManagement, bool _bValidateData)
        //    : this(Image.FromStream(_stream, _bUseEmbeddedColorManagement, _bValidateData))
        //{
        //}

        /// <summary>
        /// new UnsafeBitmap("Name.jpg") like new Bitmap("Name.jpg")
        /// </summary>
        /// <param name="_sName"></param>
        public UnsafeBitmap24(string _sName)
            : this(new Bitmap(_sName))
        {
        }

        /// <summary>
        /// like new Bitmap("Test", true) e.g.
        /// </summary>
        /// <param name="_sFileName"></param>
        /// <param name="_bUseIcm"></param>
        public UnsafeBitmap24(string _sFileName, bool _bUseIcm)
            : this(new Bitmap(_sFileName, _bUseIcm))
        {
        }

        /// <summary>
        /// Like new Bitmap(Stream, true)
        /// </summary>
        /// <param name="_stream"></param>
        /// <param name="_bUseIcm"></param>
        public UnsafeBitmap24(Stream _stream, bool _bUseIcm)
            : this(new Bitmap(_stream, _bUseIcm))
        {
        }

        /// <summary>
        /// Like new Bitmap(Bitmap)
        /// </summary>
        /// <param name="inputBitmap"></param>
        public UnsafeBitmap24(Bitmap inputBitmap)
        {
            m_WorkingBitmap = inputBitmap;
            LockImage();
            m_nHeight = m_WorkingBitmap.Height;
            m_nWidth = m_WorkingBitmap.Width;
            m_nPixelCount = m_nWidth * m_nHeight;
        }

        ////TODO: UnsafeBitmap(byte[] _aByte) this has to be tested
        ///// <summary>
        ///// Convert given byte array into bitmap
        ///// </summary>
        ///// <param name="_aByte"></param>
        ///// <param name="_pixelFormat"></param>
        //public UnsafeBitmap24(byte[] _aByte)
        //    : this(BitmapFunctions.ConvertFromMemoryStream(_aByte))
        //{
        //}

        ////TODO: this has to be implemented and tested
        ///// <summary>
        ///// 
        ///// </summary>
        ///// <param name="_aByte"></param>
        ///// <param name="_pixelFormat"></param>
        //public UnsafeBitmap24(byte[] _aByte, int _nWidth, int _nHeight, PixelFormat _pixelFormat)
        //    : this(UnsafeBitmap.ConvertToBitmap(_aByte, _pixelFormat, _nWidth, _nHeight, false))
        //{
        //}


        /// <summary>
        /// Performs an implicit conversion from <see cref="System.Drawing.Bitmap"/> to <see cref="LowLevelGraphics.UnsafeBitmap24"/>.
        /// </summary>
        /// <param name="_bitmap">The _bitmap.</param>
        /// <returns>The result of the conversion.</returns>
        public static implicit operator UnsafeBitmap24(Bitmap _bitmap)
        {
            return new UnsafeBitmap24(_bitmap);
        }

        /// <summary>
        /// Make it possible to do this: 
        /// Image image = Image.FromFile("Hello.jpg");
        /// UnsafeBitmap b = image;
        /// </summary>
        /// <param name="_image"></param>
        /// <returns></returns>
        public static implicit operator UnsafeBitmap24(Image _image)
        {
            return new UnsafeBitmap24((Bitmap)_image);
        }

        /// <summary>
        /// This enables modulo for bitmaps.
        /// </summary>
        /// <param name="_b1"></param>
        /// <param name="_b2"></param>
        /// <returns></returns>
        public static UnsafeBitmap24 operator %(UnsafeBitmap24 _b1, UnsafeBitmap24 _b2)
        {
            return null;
        }

        /// <summary>
        /// Use this to ADD two pictures.
        /// </summary>
        /// <param name="_b1"></param>
        /// <param name="_b2"></param>
        /// <returns></returns>
        public static UnsafeBitmap operator +(UnsafeBitmap24 _b1, UnsafeBitmap24 _b2)
        {
            return new Add().Process(_b1, _b2);
        }

        /// <summary>
        /// Use this to subtract two pictures.
        /// </summary>
        /// <param name="_b1"></param>
        /// <param name="_b2"></param>
        /// <returns></returns>
        public static UnsafeBitmap operator -(UnsafeBitmap24 _b1, UnsafeBitmap24 _b2)
        {
            return new Sub().Process(_b1, _b2);
        }

        /// <summary>
        /// Use this to multiplicate two pictures.
        /// </summary>
        /// <param name="_b1"></param>
        /// <param name="_b2"></param>
        /// <returns></returns>
        public static UnsafeBitmap operator *(UnsafeBitmap24 _b1, UnsafeBitmap24 _b2)
        {
            return new Multiplizieren().Process(_b1, _b2);
        }

        /// <summary>
        /// Use this two divide two pictures.
        /// </summary>
        /// <param name="_b1"></param>
        /// <param name="_b2"></param>
        /// <returns></returns>
        public static UnsafeBitmap operator /(UnsafeBitmap24 _b1, UnsafeBitmap24 _b2)
        {
            return new Divide().Process(_b1, _b2);
        }

        /// <summary>
        /// Use this for a logical not (!) of a picture. 
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public static UnsafeBitmap operator !(UnsafeBitmap24 _bitmap)
        {
            new Invert().Execute(_bitmap);
            return _bitmap;
        }

        /// <summary>
        /// Use this to logical AND (bitmap1 and bitmap2) two pictures.
        /// </summary>
        /// <param name="_b1"></param>
        /// <param name="_b2"></param>
        /// <returns></returns>
        public static UnsafeBitmap operator &(UnsafeBitmap24 _b1, UnsafeBitmap24 _b2)
        {
            return new And().Process(_b1, _b2);
        }

        /// <summary>
        /// Use this for a logical xor for two pictures (^)
        /// </summary>
        /// <param name="_b1"></param>
        /// <param name="_b2"></param>
        /// <returns></returns>
        public static UnsafeBitmap operator ^(UnsafeBitmap24 _b1, UnsafeBitmap24 _b2)
        {
            return new XOR().Process(_b1, _b2);
        }

        /// <summary>
        /// Use this for a logical or of two pictures (|)
        /// </summary>
        /// <param name="_b1"></param>
        /// <param name="_b2"></param>
        /// <returns></returns>
        public static UnsafeBitmap operator |(UnsafeBitmap24 _b1, UnsafeBitmap24 _b2)
        {
            return new OR().Process(_b1, _b2);
        }

        /// <summary>
        /// This will do a RIGHT shift
        /// </summary>
        /// <param name="_b1"></param>
        /// <param name="_nBits"></param>
        /// <returns></returns>
        public static UnsafeBitmap operator >>(UnsafeBitmap24 _b1, int _nBits)
        {
            return new ImageBitShift(_nBits).ExecuteCloned(_b1);
        }

        /// <summary>
        /// This will do a LEFT bitshift
        /// </summary>
        /// <param name="_b1"></param>
        /// <param name="_nBits"></param>
        /// <returns></returns>
        public static UnsafeBitmap operator <<(UnsafeBitmap24 _b1, int _nBits)
        {
            return new ImageBitShift(_nBits).ExecuteCloned(_b1);
        }

        /// <summary>
        /// Tries to lock the image
        /// </summary>
        /// <returns>TRUE =&gt; Success, FALSE =&gt; bad luck</returns>
        public override bool LockImage()
        {
            unsafe
            {
                this.m_PixelFormat = PixelFormat.Format24bppRgb;
                if (m_WorkingBitmap == null) return false;
                Rectangle bounds = new Rectangle(Point.Empty, m_WorkingBitmap.Size);

                width = (int)(bounds.Width * sizeof(PixelData));
                if (width % 4 != 0) width = 4 * (width / 4 + 1);

                //Lock Image
                m_BitmapData = m_WorkingBitmap.LockBits(bounds, ImageLockMode.ReadWrite, m_PixelFormat);
                m_pBase = (Byte*)m_BitmapData.Scan0.ToPointer();
            }
            return true;
        }
    }

}
